package com.dbflow5.processor.utils;

import com.dbflow5.annotation.ColumnIgnore;
import com.dbflow5.processor.ProcessorManager;
import com.squareup.javapoet.ClassName;

import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.List;

/**
 * Description:
 */
public class ElementUtility {

    /**
     * real full-set of elements
     *
     * @param element element
     * @param manager manager
     * @return real full-set of elements, including ones from super-class.
     */
    public static List<Element> getAllElements(TypeElement element, ProcessorManager manager) {
        List<Element> elements = new ArrayList<>(manager.elements.getAllMembers(element));
        TypeMirror superMirror;
        TypeElement typeElement = element;
        if(typeElement != null){
            superMirror = typeElement.getSuperclass();
            while (typeElement.getSuperclass() != null) {
                typeElement = (TypeElement)manager.typeUtils.asElement(superMirror);
                if(typeElement != null){
                    List<Element> superElements = (List<Element>)manager.elements.getAllMembers(typeElement);
                    for (Element it : superElements) {
                        if (!elements.contains(it)) {
                            elements.add(it);
                        }
                    }
                }
            }
        }
        return elements;
    }

    public static boolean isInSamePackage(ProcessorManager manager, Element elementToCheck, Element original) {
        return manager.elements.getPackageOf(elementToCheck).toString() == manager.elements.getPackageOf(original).toString();
    }

    public static boolean isPackagePrivate(Element element) {
        return !element.getModifiers().contains(Modifier.PUBLIC) && !element.getModifiers().contains(Modifier.PRIVATE)
            && !element.getModifiers().contains(Modifier.STATIC);
    }

    public static boolean isValidAllFields(boolean allFields, Element element) {
        return allFields && element.getKind().isField() &&
            !element.getModifiers().contains(Modifier.STATIC) &&
            !element.getModifiers().contains(Modifier.FINAL) &&
            ElementExtensions.annotation(ColumnIgnore.class, element) == null;
    }

    /**
     * Attempts to retrieve a [ClassName] from the [elementClassname] Fully-qualified name. If it
     * does not exist yet via [ClassName.get], we manually create the [ClassName] object to reference
     * later at compile time validation.
     *
     * @param elementClassname elementClassname
     * @param manager manager
     * @return ClassName
     */
    public static ClassName getClassName(String elementClassname, ProcessorManager manager) {
        TypeElement typeElement = manager.elements.getTypeElement(elementClassname);
        if (typeElement != null) {
            return ClassName.get(typeElement);
        } else {
            String[] names = elementClassname.split(".");
            if (names.length > 0) {
                // attempt to take last part as class name
                String className = names[names.length - 1];
                return ClassName.get(elementClassname.replace("." + className, ""), className);
            } else {
                return null;
            }
        }
    }
}
